﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Xml;
using SharpObjects.Configuration;
using SharpObjects.Configuration.ConfigurationProviders;
using SharpObjects.Interfaces;
using SharpObjects.RuleEngine.RuleElements;
using SharpObjects.RuleEngine;

namespace SharpObjects.RuleEngine.Rules
{
    public class IsEqualRule : IXmlInitializable, IRule
    {
        public string Output { get; set; }
        public bool IsCaseSensitive { get; set; }
        public FieldElement Field { get; set; }
        public ValueElement Value { get; set; }
        
        #region IInitializable Members

        public void Initialize(XmlElement initializationElement)
        {
            XmlConfigurationProvider init = new XmlConfigurationProvider(initializationElement);

            Output = init.GetString("@output");
            IsCaseSensitive = init.GetBoolean("@case_sensitive", false);
            Field = init.GetObject<FieldElement>("field");
            Value = init.GetObject<ValueElement>("value");

            if (Field.FieldType != Value.ValueType)
            {
                throw new ArgumentException("Types of the Field and the Value don't match");
            }

            this.IsInitialized = true;
        }

        public bool IsInitialized { get; set; }

        #endregion

        #region IRule Members

        public void Execute(ref IRuleEngineContext ruleEngineContext, IDataProvider dataProvider)
        {

            switch (Field.FieldType)
            {
                case eFieldType.String:
                    {
                        string fieldValue = (string)Field.GetValue(ruleEngineContext, dataProvider);
                        string value = (string)Value.Value;

                        if (!IsCaseSensitive)
                        {
                            fieldValue = fieldValue.ToLower();
                            value = value.ToLower();
                        }

                        bool result = fieldValue == value;
                        ruleEngineContext.SetValue<bool>(Output, result);
                    }
                    break;
                case eFieldType.Int:
                    {
                        int fieldValue = (int)Field.GetValue(ruleEngineContext, dataProvider);
                        int value = (int)Value.Value;

                        bool result = fieldValue == value;
                        ruleEngineContext.SetValue<bool>(Output, result);
                    }
                    break;
                case eFieldType.Double:
                    {
                        double fieldValue = (double)Field.GetValue(ruleEngineContext, dataProvider);
                        double value = (double)Value.Value;

                        bool result = fieldValue == value;
                        ruleEngineContext.SetValue<bool>(Output, result);
                    }
                    break;
                case eFieldType.DateTime:
                    {
                        DateTime fieldValue = (DateTime)Field.GetValue(ruleEngineContext, dataProvider);
                        DateTime value = (DateTime)Value.Value;

                        bool result = fieldValue == value;
                        ruleEngineContext.SetValue<bool>(Output, result);
                    }
                    break;
                case eFieldType.Bool:
                    {
                        bool fieldValue = (bool)Field.GetValue(ruleEngineContext, dataProvider);
                        bool value = (bool)Value.Value;

                        bool result = fieldValue == value;
                        ruleEngineContext.SetValue<bool>(Output, result);
                    }
                    break;
                default:
                    throw new ArgumentException("Unknown eFieldType enum value: " + Field.FieldType);
            }
        }

        #endregion
    }
}
